/*
 * compressor.cpp
 *
 *  Created on: 2009-1-10
 *      Author: ant
 */

#include "compressor.h"
#include "common_struct.h"
#include "file_sender.h"
#include "utility.h"

using namespace toxic;

Compressor::Compressor(FileSender* sender)
:sender_(sender) {

}

Compressor::~Compressor() {

}

static int computeCompressionRatio(size_t originalSize, size_t compressedSize) {
	double ratio = 1.0;
	if (originalSize != 0) {
		ratio = (static_cast<double>(compressedSize) / static_cast<double>(originalSize)) + 0.005;
	}
	return static_cast<int>(ratio * 100);
}

void Compressor::process(JobArgument* job) {
	if (job == 0) {
		xerror << "null pointer {job}, at {void Compressor::process(JobArgument* job)}";
		return;
	}

	xdebug << "accept new job: time {" << *job->time
		<< "}, action count {" << job->actions.size() << "}";

	size_t actionIndex = 1;
	foreach (Action* action, job->actions) {

		Rule& rule = action->rule;
		list<Source> expandedSources;

		xtrace << "start processing action {" << actionIndex
			<< "}, rule name {" << rule.name << "}, sources\n" << rule.sources;

		size_t sourceIndex = 1;
		foreach (const Source& source, rule.sources) {

			string pathname(source.pathname);
			string filename = toxic::filename(pathname);
			bool hasWildcard = (filename.find_last_of("*?") != string::npos);

			if (hasWildcard) {
				pathname = toxic::dirname(pathname);
			}

			if (!toxic::exists(pathname)) {
				xwarn << "the file or directory does not exist {" << pathname << "}";
				++sourceIndex;
				continue;
			}

			Source temp;
			temp.compress = source.compress;

			if (!source.compress) {
				if (!toxic::isDirectory(pathname)) {
					temp.pathname = pathname;
					expandedSources.push_back(temp);
					xtrace << "(" << sourceIndex << ") skip regular file {" << pathname
						<< "}, no need to compress or expend";
				}
				else  {
					vector<string> result;
					if (hasWildcard) {
						traverseDirectoryWithPattern(result, filename, pathname, 1);
					}
					else {
						traverseDirectory(result, pathname, 1);
					}

					foreach (const string& pathname, result) {
						temp.pathname = pathname;
						expandedSources.push_back(temp);
					}

					if (hasWildcard) {
						xtrace << "(" << sourceIndex << ") expand directory {" << pathname
							<< "}, pattern {" << filename
							<< "}, expended file count {" << result.size() << "}\n" << result;
					}
					else {
						xtrace << "(" << sourceIndex << ") expand directory {" << pathname
							<< "}, expended file count {" << result.size() << "}\n" << result;
					}
				}
			}
			else {
				temp.pathname = pathname + ".tar.gz";
				expandedSources.push_back(temp);

				size_t originalSize = 0;
				size_t compressedSize = 0;

				if (hasWildcard) {
					xtrace << "(" << sourceIndex << ") start compressing file {" << source.pathname
						<< "}, size {" << (originalSize = getFileSizeWithPattern(pathname, filename)) << "} bytes";

					compress(source.pathname, temp.pathname);
				}
				else {
					xtrace << "(" << sourceIndex << ") start compressing file {" << pathname
						<< "}, size {" << (originalSize = getFileSize(pathname)) << "} bytes";

					compress(pathname, temp.pathname);
				}

				xtrace << "(" << sourceIndex << ") compressed size {" << (compressedSize = getFileSize(temp.pathname)) << "} bytes";
				xtrace << "(" << sourceIndex << ") compression ratio {" << computeCompressionRatio(originalSize, compressedSize) << "%}";
			}

			++sourceIndex;
		}

		rule.sources = expandedSources;
		++actionIndex;
	}

	xdebug << "finish processing job: time {" << *job->time
		<< "}, action count {" << job->actions.size() << "}";
	// notify sender
	sender_->push(job);
}
